{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在计算机程序的开发过程中，随着程序代码越写越多，在一个文件里代码就会越来越长，越来越不容易维护。\n",
    "\n",
    "为了编写可维护的代码，我们把很多函数分组，分别放到不同的文件里，这样，每个文件包含的代码就相对较少，很多编程语言都采用这种组织代码的方式。在Python中，一个.py文件就称之为一个模块（Module）。\n",
    "\n",
    "- 使用模块有什么好处？\n",
    "\n",
    "最大的好处是大大提高了代码的可维护性。其次，编写代码不必从零开始。当一个模块编写完毕，就可以被其他地方引用。我们在编写程序的时候，也经常引用其他模块，包括Python内置的模块和来自第三方的模块。\n",
    "\n",
    "使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中，因此，我们自己在编写模块时，不必考虑名字会与其他模块冲突。但是也要注意，尽量不要与内置函数名字冲突。点这里查看Python的所有内置函数。\n",
    "\n",
    "你也许还想到，如果不同的人编写的模块名相同怎么办？为了避免模块名冲突，Python又引入了按目录来组织模块的方法，称为包（Package）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结\n",
    "模块是一组Python代码的集合，可以使用其他模块，也可以被其他模块使用。\n",
    "\n",
    "创建自己的模块时，要注意：\n",
    "\n",
    "- 模块名要遵循Python变量命名规范，不要使用中文、特殊字符；\n",
    "- 模块名不要和系统模块名冲突，最好先查看系统是否已存在该模块，检查方法是在Python- 交互环境执行import abc，若成功则说明系统存在此模块。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 使用模块\n",
    "\n",
    "Python本身就内置了很多非常有用的模块，只要安装完毕，这些模块就可以立刻使用。\n",
    "\n",
    "我们以内建的sys模块为例，编写一个hello的模块："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Too many arguments!\n"
     ]
    }
   ],
   "source": [
    "#!/usr/bin/env python3\n",
    "# -*- coding: utf-8 -*-\n",
    "\n",
    "' a test module '\n",
    "\n",
    "__author__ = 'Michael Liao'\n",
    "\n",
    "import sys\n",
    "\n",
    "def test():\n",
    "    args = sys.argv\n",
    "    if len(args)==1:\n",
    "        print('Hello, world!')\n",
    "    elif len(args)==2:\n",
    "        print('Hello, %s!' % args[1])\n",
    "    else:\n",
    "        print('Too many arguments!')\n",
    "\n",
    "if __name__=='__main__':\n",
    "    test()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "第1行和第2行是标准注释，第1行注释可以让这个hello.py文件直接在Unix/Linux/Mac上运行，第2行注释表示.py文件本身使用标准UTF-8编码；\n",
    "\n",
    "第4行是一个字符串，表示模块的文档注释，任何模块代码的第一个字符串都被视为模块的文档注释；\n",
    "\n",
    "第6行使用__author__变量把作者写进去，这样当你公开源代码后别人就可以瞻仰你的大名；\n",
    "\n",
    "以上就是Python模块的标准文件模板，当然也可以全部删掉不写，但是，按标准办事肯定没错。\n",
    "\n",
    "后面开始就是真正的代码部分。\n",
    "\n",
    "你可能注意到了，使用sys模块的第一步，就是导入该模块："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "导入sys模块后，我们就有了变量sys指向该模块，利用sys这个变量，就可以访问sys模块的所有功能。\n",
    "\n",
    "sys模块有一个argv变量，用list存储了命令行的所有参数。argv至少有一个元素，因为第一个参数永远是该.py文件的名称，例如：\n",
    "\n",
    "运行python3 hello.py获得的sys.argv就是['hello.py']；\n",
    "\n",
    "运行python3 hello.py Michael获得的sys.argv就是['hello.py', 'Michael]。\n",
    "\n",
    "最后，注意到这两行代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Too many arguments!\n"
     ]
    }
   ],
   "source": [
    "if __name__=='__main__':\n",
    "    test()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当我们在命令行运行hello模块文件时，Python解释器把一个特殊变量 __ name __ 置为__ main __，而如果在其他地方导入该hello模块时，if判断将失败，因此，这种if测试可以让一个模块通过命令行运行时执行一些额外的代码，最常见的就是运行测试。\n",
    "\n",
    "我们可以用命令行运行hello.py看看效果"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 作用域\n",
    "在一个模块中，我们可能会定义很多函数和变量，但有的函数和变量我们希望给别人使用，有的函数和变量我们希望仅仅在模块内部使用。在Python中，是通过_前缀来实现的。\n",
    "\n",
    "正常的函数和变量名是公开的（public），可以被直接引用，比如：abc，x123，PI等；\n",
    "\n",
    "类似__ xxx __ 这样的变量是特殊变量，可以被直接引用，但是有特殊用途，比如上面的 __ author __ ，__ name __ 就是特殊变量，hello模块定义的文档注释也可以用特殊变量 __ doc __ 访问，我们自己的变量一般不要用这种变量名；\n",
    "\n",
    "类似 _ xxx和 __ xxx这样的函数或变量就是非公开的（private），不应该被直接引用，比如  _ abc， __ abc等；\n",
    "\n",
    "之所以我们说，private函数和变量“不应该”被直接引用，而不是“不能”被直接引用，是因为Python并没有一种方法可以完全限制访问private函数或变量，但是，从编程习惯上不应该引用private函数或变量。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "private函数或变量不应该被别人引用，那它们有什么用呢？请看例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def _private_1(name):\n",
    "    return 'Hello, %s' % name\n",
    "\n",
    "def _private_2(name):\n",
    "    return 'Hi, %s' % name\n",
    "\n",
    "def greeting(name):\n",
    "    if len(name) > 3:\n",
    "        return _private_1(name)\n",
    "    else:\n",
    "        return _private_2(name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们在模块里公开greeting()函数，而把内部逻辑用private函数隐藏起来了，这样，调用greeting()函数不用关心内部的private函数细节，这也是一种非常有用的代码封装和抽象的方法，即：\n",
    "\n",
    "- 外部不需要引用的函数全部定义成private，只有外部需要引用的函数才定义为public。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 安装第三方模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在命令提示符窗口下尝试运行pip\n",
    "# 安装Pillow的命令：\n",
    "pip install Pillow"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "推荐直接使用Anaconda，这是一个基于Python的数据处理和科学计算平台，它已经内置了许多非常有用的第三方库，我们装上Anaconda，就相当于把数十个第三方模块自动安装好了，非常简单易用。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 模块搜索路径\n",
    "当我们试图加载一个模块时，Python会在指定的路径下搜索对应的.py文件，如果找不到，就会报错："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "ename": "ModuleNotFoundError",
     "evalue": "No module named 'mymodul'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-15-0ab3e58aa1f1>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mimport\u001b[0m \u001b[0mmymodul\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'mymodul'"
     ]
    }
   ],
   "source": [
    "import mymodul"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "默认情况下，Python解释器会搜索当前目录、所有已安装的内置模块和第三方模块，搜索路径存放在sys模块的path变量中："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['C:\\\\Users\\\\Ivan\\\\学习笔记\\\\Python教程-廖雪峰老师\\\\05.模块',\n",
       " 'D:\\\\Anaconda3\\\\python37.zip',\n",
       " 'D:\\\\Anaconda3\\\\DLLs',\n",
       " 'D:\\\\Anaconda3\\\\lib',\n",
       " 'D:\\\\Anaconda3',\n",
       " '',\n",
       " 'D:\\\\Anaconda3\\\\lib\\\\site-packages',\n",
       " 'D:\\\\Anaconda3\\\\lib\\\\site-packages\\\\win32',\n",
       " 'D:\\\\Anaconda3\\\\lib\\\\site-packages\\\\win32\\\\lib',\n",
       " 'D:\\\\Anaconda3\\\\lib\\\\site-packages\\\\Pythonwin',\n",
       " 'D:\\\\Anaconda3\\\\lib\\\\site-packages\\\\IPython\\\\extensions',\n",
       " 'C:\\\\Users\\\\Ivan\\\\.ipython']"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import sys\n",
    "sys.path"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 添加自己的搜索目录，有两种方法："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一是直接修改sys.path，添加要搜索的目录："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 这种方法是在运行时修改，运行结束后失效。\n",
    "import sys\n",
    "sys.path.append('/Users/michael/my_py_scripts')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "第二种方法是设置环境变量PYTHONPATH，该环境变量的内容会被自动添加到模块搜索路径中。设置方式与设置Path环境变量类似。注意只需要添加你自己的搜索路径，Python自己本身的搜索路径不受影响。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
